package com.cictec.middleware.gps.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.cictec.middleware.commons.cache.ecache.EHCacheUtils;
import com.cictec.middleware.commons.utils.DateUtils;
import com.cictec.middleware.commons.utils.FileUtils;
import com.cictec.middleware.commons.utils.PMSUtils;
import com.cictec.middleware.commons.utils.PropertiesUtils;
import com.cictec.middleware.core.entity.BusTimingPointSupply;
import com.cictec.middleware.gps.engine.TimingPoint;
import com.cictec.middleware.gps.engine.send.SendHandler;
import com.cictec.middleware.gps.engine.service.DataStorageToRedisService;
import com.cictec.middleware.gps.service.feign.MiddlewareDcFeignClient;

/**
 * 位置、进出站原始信息存储服务
 * 
 * @author ql
 *
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
@Service
public class BusTimingPointService {

	private static Logger logger = LoggerFactory.getLogger(BusTimingPointService.class);

	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private DataStorageToRedisService dataStorageToRedisService;
	@Autowired
	private MiddlewareDcFeignClient middlewareDcFeignClient;
	
	


	@PostConstruct
	public void init() {
		int threads = PropertiesUtils.getIntValue("system.parameter.position.threads", 2);
		logger.debug("【 BusTimingPointService 】创建 时序对象存储线程池, 线程池大小{}", threads);
	}
	

	/**
	 *【数据库】查询需要重新计算里程的 车辆信息
	 * @param date	yyyy-MM-dd  不为空时，查询指定时间内的
	 * @param isSupply	true:只查询有补传记录的，false：所有
	 * @return
	 */
	public List<BusTimingPointSupply> selectListBusTimingPointSupply(String date, boolean isSupply){
		List<BusTimingPointSupply> list = middlewareDcFeignClient.selectListBusTimingPointSupply(date, isSupply);
		return list;
	}
	
	
	/**
	 * 【数据库】新增，修改数据存储标识
	 * @param devCode
	 * @param date		yyyy-MM-dd
	 * @param supFlag	时序对象补传标识（0：未补传数据，1：有补传数据）
	 * @param supRepairFlag	里程是否以修复（0：默认没有补传或已修复，1:未修复）
	 */
	public void saveTimingPointSupply(String devCode, String date, String supFlag, String supRepairFlag){
		
		middlewareDcFeignClient.saveTimingPointSupply(devCode, date, supFlag, supRepairFlag);
	}
	
	
	/**
	 * 【实时计算】
	 * <br>1、保存【当天】时序对象信息到redis,如果超过 day天前的数据，也会存储，但不会参与计算
	 * <br>2、保存【设定天数内的】时序补传数据到数据库;
	 * @param busInstance	实时对象
	 * @param timingPoint 	当前时序对象
	 */
	public void saveTimePoint(TimingPoint timingPoint){
		
		Date time = timingPoint.getTime();
		String pointDate = DateUtils.formatDate(time);

		Date currentTime = new Date();
		String devCode = timingPoint.getDevCode();
		int saveDays = PropertiesUtils.getIntValue("system.parameter.position.day", 10);
		Date dayTime = DateUtils.getDateFromDate(DateUtils.getStartDateTime(currentTime), -saveDays);	// 指定前 day天的时间  yyyy-MM-dd 00:00:00
		Date yesterday = DateUtils.getEndDateTime(DateUtils.getDateFormatFromDate(currentTime, -1)); 	// 系统当前时间的昨天 yyyy-MM-dd 23:59:59
		
		// 只处理指定时间内的隔天补传数据
		if(dayTime.getTime() <= time.getTime() && time.getTime() <= yesterday.getTime()){
			
//			insertTimingPoint(timingPoint); // 保存隔天补传数据
			List<TimingPoint> dataList = new ArrayList<>();
			SendHandler.sendBusPostionSaveFromSeda(pointDate, devCode, dataList, null);	// 发送保存原始数据到队列
			
			String cacheName = "bus-timing-point-supply";
			String cacheKey = devCode + "-" + pointDate;
			BusTimingPointSupply supply = EHCacheUtils.getValue(cacheName, cacheKey);
			
			if(supply == null){
				supply = new BusTimingPointSupply();
				supply.setSupDevCode(devCode);
				supply.setSupDate(pointDate);
				supply.setSupFlag("1");			//时序对象补传标识（0：未补传，1：有补传）
				
				saveTimingPointSupply(devCode, pointDate, "1", "1");	// 新增或更新
				
				EHCacheUtils.setValue(cacheName, cacheKey, supply);
			}
			
			logger.debug("【BusTimingPointService】保存历史数据");
		}else{
			
			String currentDate = DateUtils.getDate();// 当前日期
			if(pointDate.equals(currentDate)){
				// 保存当天的时序对象信息；如果超过 day天前的数据，也会存储，但不会参与计算的
				dataStorageToRedisService.savePositionTMRedis(devCode, timingPoint);
			}else{
				logger.error("位置点异常数据,-TM不存储：time:{}, {}", DateUtils.formatDateTimes(time), JSON.toJSONString(timingPoint));
			}
		}
	}
	
	/**
	 * 删除redis指定日期的时序对于原始信息，key: YYYYMMDD-*-TM
	 * @param date
	 */
	public void deleteTimingPointFromRedis(String date){
		
		logger.debug("删除redis {} 的时序对象信息开始", date);
		List<String> busPositionKeys = dataStorageToRedisService.getPositionTMKeysFromRedis(date);
		for (String redisKey : busPositionKeys) {
			stringRedisTemplate.delete(redisKey);
			logger.debug("删除redis： {}  ", redisKey);
		}
		logger.debug("删除redis {} 的时序对象信息完成", date);
	}
	
	/**
	 * 【定时任务】保存redis时序对象信息到数据库
	 * @param date yyyy-MM-dd
	 */
	
	public void saveTimePointFromRedisTodb(String date) {
		// 保存数据到数据库
		// String yesterday = DateUtils.getDateFormatFromDate(new Date(), -1);
		List<String> busPositionKeys = dataStorageToRedisService.getPositionTMKeysFromRedis(date);
		logger.debug("保存 {} 时序对象数据到数据库 ,总计 {} 条", date, busPositionKeys.size());

		int count = 0;
		for (String redisKey : busPositionKeys) {
			count++;
			// executorService.execute(new ExcuteSaveTimingPointTask(date, redisKey, count));

			try {

				String[] keySplit = redisKey.split("-");
				List<TimingPoint> positionList = dataStorageToRedisService.getPositionTMFromRedis(date, keySplit[1], false);

				if (positionList.size() > 0) {
					// insterBatchTimingPoint(positionList);

					String devCode = positionList.get(0).getDevCode();
					saveTimingPointSupply(devCode, date, "0", "0"); // 新增或更新

					
					Map data = new HashMap();
					data.put("devCode", devCode);
					data.put("date", date);
					
					List<TimingPoint> list = new ArrayList<TimingPoint>();
					list.addAll(positionList);
					data.put("jsonData", JSON.toJSONString(list));
					data.put("redisKeyTM", redisKey);
					writeData(data);
				}
			} catch (Exception e) {
				e.printStackTrace();
				logger.debug("保存 {} 时序对象到数据库  第{}条:错误！！！！！！{}", redisKey, count, e);
			}
			logger.debug("保存 {} 时序对象到数据库  第{}条:", redisKey, count);
		}

	}
	
	/**
	 * 一行行写入
	 */
	public void writeData(Map dataMap ){
		
		String devCode = PMSUtils.isNull(dataMap.get("devCode"));
		String date = PMSUtils.isNull(dataMap.get("date"));
//		String jsonType = PMSUtils.isNull(dataMap.get("jsonType"));
		String jsonData = PMSUtils.isNull(dataMap.get("jsonData"));
		if(dataMap.containsKey("redisKeyTM")){
			try {
				String redisKeyTM = PMSUtils.isNull(dataMap.get("redisKeyTM"));
				stringRedisTemplate.delete(redisKeyTM);
				logger.debug("删除redis： {}  ", redisKeyTM);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		
		String basePath = PropertiesUtils.getString("middleware.dbfile.path");
		if (!PMSUtils.isEmpty(basePath)) {
			
			String filePath = basePath + File.separator + date + File.separator + devCode + ".json";
			filePath = basePath + "/" + date + "/" + devCode + ".json";
			
			FileUtils.createFile(filePath);
			FileUtils.write(filePath, true, jsonData, true);
		}
		
//		List<TimingPoint> readList = readData(date, devCode);
//		System.out.println(readList.size());
//		for (TimingPoint timingPoint : readList) {
//			System.out.println(DateUtils.formatDateTimes(timingPoint.getTime()));
//		}
	}
	
	/**
	 * 从文件中读取设备位置信息
	 * @param date
	 * @param devCode
	 * @return
	 */
	public List<TimingPoint> readData(String date, String devCode){
		
		String basePath = PropertiesUtils.getString("middleware.dbfile.path");
		
		String filePath = basePath + "/" + date + "/" + devCode + ".json";
		
		
		List<TimingPoint> list = new ArrayList();
		BufferedReader in = null;
		try {
			
			File srcFile = new File(filePath);
			if (!srcFile.exists()) {
				logger.error("位置信息源文件 不存在：{} !!!!!!!!!!!!!!!!!!", filePath);
				return list;
			}

			
			in = new BufferedReader(new FileReader(srcFile));
			String s;
			try {
				while ((s = in.readLine()) != null){
					if(!PMSUtils.isEmpty(s)){
						String flag = s.substring(0, 1);
						if(flag.equals("[")){
							
							/***** 中间件重构，支持老的原始数据读取 start **********/
							String oldValueStart = s.substring(0, 10);
							if(oldValueStart.equals("[{\"status\"")){
								List<Map> data = JSON.parseArray(s, Map.class);
								for (Map map : data) {
									TimingPoint _point = new TimingPoint();
									String _time = PMSUtils.isNull(map.get("time"));
									_point.setTime(new Date(Long.parseLong(_time)));
									Map tmp = (Map)map.get("status");
									Map _data = new HashMap();
									_data.putAll(tmp);
									_point.setAttributes(_data);
//									_point.setAttribute("trigger_type", "0");
									list.add(_point);
								}
								continue;
							}
							/***** 中间件重构，支持老的原始数据读取  ent **********/
							
							List<TimingPoint> tmp = JSON.parseArray(s, TimingPoint.class);
							list.addAll(tmp);
						}else if(flag.equals("{")){
							TimingPoint tmp = JSON.parseObject(s, TimingPoint.class);
							list.add(tmp);
						}
					}
				}
			} finally {
				in.close();
			}
		} catch (IOException e) {
//			e.printStackTrace();
			logger.error("读取文件错误：{}", e);
		}
		
		
		// 按照时间排序
		list.sort(new Comparator<TimingPoint>() {
			@Override
			public int compare(TimingPoint o1, TimingPoint o2) {
				
				long c = o1.getTime().getTime() - o2.getTime().getTime();
				return (int)c;
				
			}
		});
		
		
		return list;
	}
	
}
